package se.webbzon.boltzmann.minigame.sandbox;

import java.awt.Image;
import java.awt.Rectangle;

import se.webbzon.boltzmann.configuration.Controls;
import se.webbzon.boltzmann.input.Button;
import se.webbzon.boltzmann.input.Input;
import se.webbzon.boltzmann.input.InputListener;
import se.webbzon.boltzmann.minigame.effect.SandBoxFeedback;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.oschi01.resourceset.ResourceSet;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;
import se.webbzon.oschi01.worldobject.WorldObject;

public class SandBoxCursor extends DefaultSandBoxItem {
	
	// The maximal speed of the cursor
	private static final double maxSpeed = 12;
	
	// The cooldown of the poking image
	private static final int pokeCooldown = 5;
	
	// The size of the cursor
	private static final double width = 32, height = 32;
	
	// The image sets of this cursor
	private static final ResourceSet<Image> grab, hold, poke;
	static {
		grab = Resources.getImageSet("minigame_cursor_grab");
		hold = Resources.getImageSet("minigame_cursor_hold");
		poke = Resources.getImageSet("minigame_cursor_poke");
	}
	
	// The current image set of the cursor
	private static ResourceSet<Image> current;
	private int pokeRemaining;
	
	// Whatever the cursor is visible
	private boolean visible;
	
	// The velocity of this cursor
	private int xVelocity, yVelocity;
	
	// The input listener of this sand box item
	private final InputListener listener;
	
	// The current sand box of this sand box item
	private SandBox box;
	
	// The item which is dragged by the cursor
	private SandBoxItem item;
	
	
	/*============================================================
	Constructors
	============================================================*/
	
	public SandBoxCursor() {
		current = grab;
		setInstance(new Instance());
		setSize(width,height);
		listener = new InputListenerImpl();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the item grabbed by this cursor. **/
	public SandBoxItem getItem() {
		return item;
	}

	/** Sets the item grabbed by this cursor. **/
	public void setItem(SandBoxItem item) {
		this.item = item;
	}
	
	/** Returns true if the cursor is visible. **/
	public boolean isVisible() {
		return visible;
	}
	
	/** Sets whatever the cursor is visible. **/
	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	@Override public boolean draggable() {
		return false;
	}

	@Override public boolean droppable() {
		return false;
	}
	
	/*============================================================
	Protected Methods
	============================================================*/
	
	@Override protected Instance getInstance() {
		return (Instance) super.getInstance();
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Returns the horizontal velocity of this cursor. **/
	private int getXVelocity() {
		return xVelocity;
	}

	/** Returns the vertical velocity of this cursor. **/
	private int getYVelocity() {
		return yVelocity;
	}

	/** Sets the velocity of this cursor. **/
	private void setVelocity(int xVelocity, int yVelocity) {
		this.xVelocity = xVelocity;
		this.yVelocity = yVelocity;
	}
	
	/*============================================================
	Private Classes
	============================================================*/

	/** The cursor instance. **/
	private final class Instance extends SandBoxObject {

		public Instance() {
			super(WorldObject.onStep + WorldObject.onPostDraw, 1);
		}
		
		@Override public void onAttach(SandBox box) {
			Rectangle rect = new Rectangle();
			box.getBoundary(rect);
			setPosition((int) rect.getCenterX(),(int) rect.getCenterY());
			setVisible(true);
			Controls.instance().getInput().addListener(listener);
			SandBoxCursor.this.box = box;
		}

		@Override public void onDetach(SandBox box) {
			setVisible(false);
			Controls.instance().getInput().removeListener(listener);
			SandBoxCursor.this.box = null;
		}

		@Override public void onStep(WorldArea world) {
			super.onStep(world);
			double xn = getX() + getXVelocity(), yn = getY() + getYVelocity(); 
			if (box.isWithinSandbox(xn, yn))
				setPosition(xn,yn);
			SandBoxItem item = getItem();
			if (item != null)
				item.setPosition(getX(), getY());
			if (pokeRemaining > 0) {
				pokeRemaining--;
			} else if (pokeRemaining == 0 && current == poke) {
				current = grab;
			}
		}
		
		@Override public void onPostDraw(WorldArea world, WorldCameraPane hud) {
			int w = (int) getWidth(), h = (int) getHeight();
			int x = (int) getX() - w/2, y = (int) getY() - h/2;
			hud.drawImage(current.get(0), x, y, w, h);
		}

		@Override public SandBoxIcon createIcon() {
			return null;
		}
		
	}

	/** An implementation of an input listener. **/
	private final class InputListenerImpl implements InputListener {

		@Override public void primaryAxisChanged(Input input, double direction, double value) {
			int vx = (int) (maxSpeed * value * Math.cos(direction));
			int vy = (int) (- maxSpeed * value * Math.sin(direction));
			setVelocity(vx,vy);
		}

		@Override public void secondaryAxisChanged(Input input, double direction, double value) {};

		@Override public void buttonPressed(Input input, Button button) {
			SandBox box = SandBoxCursor.this.box;
			if (button == Button.ACTION) {
				SandBoxItem item = getItem();
				if (item == null) {
					item = box.pick(getX(), getY());
					if (item != null) {
						current = hold;
						box.getInfo().setText("Drop " + item + " with the action button");
						setItem(item);
					} else if (pokeRemaining == 0) {
						current = poke;
						pokeRemaining = pokeCooldown;
						SandBoxItem feedback = SandBoxFeedback.createInvocation(box);
						feedback.setPosition(getX(), getY());
						box.addItem(feedback);
					}
				} else {
					current = grab;
					box.getInfo().setText(null);
					SandBoxContainer container = box.drop(item);
					if (container != null | item.droppable())
						setItem(null);
				}
			}
		}

		@Override public void buttonReleased(Input input, Button button) {};

		@Override public void bindingAccepted(Input input, Button button) {};

	}

	@Override public SandBoxIcon createIcon() {
		return null;
	}

}
